package com.quectel.business.dms.application.access.accessor.im.impl;

import com.google.common.base.Preconditions;
import com.quectel.business.common.device.DeviceExtraAttrCls;
import com.quectel.business.dms.application.ApplicationAccessConf;
import com.quectel.business.dms.application.access.accessor.im.AbstractIntelligentMonitorAccessor;
import com.quectel.business.dms.application.access.accessor.im.model.PlaybackPart;
import com.quectel.business.dms.application.access.accessor.im.model.StreamResp;
import com.quectel.business.dms.application.access.basemodel.ApplicationOriginDevice;
import com.quectel.business.dms.device.DeviceBusiness;
import com.quectel.core.module.application.dto.ApplicationDto;
import com.quectel.core.module.application.service.ApplicationService;
import com.quectel.core.module.device.dto.DeviceCommandTemplateDto;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.device.service.DeviceService;
import com.quectel.core.module.device.service.DeviceTypeService;
import com.quectel.sdk.hikisc.HikClientBuilder;
import com.quectel.sdk.hikisc.constant.HikIscConstants;
import com.quectel.sdk.hikisc.monitor.MonitorClient;
import com.quectel.sdk.hikisc.monitor.model.EncodeDeviceDetailResp;
import com.quectel.sdk.hikisc.monitor.model.SyncCameraResp;
import com.quectel.util.common.JacksonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author rananxin
 * @date 2021/12/1 9:37 上午
 */
@Component
@Slf4j
public class HikMonitorAccessorImpl extends AbstractIntelligentMonitorAccessor {

    @DubboReference
    private DeviceTypeService deviceTypeService;
    @DubboReference
    private DeviceService deviceService;
    @DubboReference
    private ApplicationService applicationService;
    @Autowired
    private DeviceBusiness deviceBusiness;

    private static final List<HikIscConstants.EventEnum> EVENT_ENUMS = new ArrayList<>();

    static {
        EVENT_ENUMS.add(HikIscConstants.EventEnum.HIGH_TOSS_ACT);
        EVENT_ENUMS.add(HikIscConstants.EventEnum.REGIONAL_INVASION);
        EVENT_ENUMS.add(HikIscConstants.EventEnum.LICENSE_PLATE_CAPTURE);
        EVENT_ENUMS.add(HikIscConstants.EventEnum.FACE_CAPTURE);
    }

    @Override
    public boolean initApplication(ApplicationDto application) {
        return syncOrRegisterDevices(application, null) && subscribeEvents(application);
    }


    @Override
    public boolean syncOrRegisterDevices(ApplicationDto application, List<ApplicationOriginDevice> devices) {
        final Date currentDate = new Date();

        ApplicationAccessConf.TemplateOfHikIscConf templateOfHikIscConf = ApplicationAccessConf
                .parseExtStr(ApplicationAccessConf.TemplateOfHikIscConf.class, application.getAccessConf());

        try {
            assert templateOfHikIscConf != null;
            MonitorClient monitorInstance = HikClientBuilder.builder()
                    .ak(templateOfHikIscConf.getAk())
                    .sk(templateOfHikIscConf.getSk())
                    .host(templateOfHikIscConf.getHost())
                    .build(MonitorClient.class);

            List<SyncCameraResp> syncCameraResps = monitorInstance.drawResources();

            List<DeviceDto> deviceDtos = new ArrayList<>();

            Map<String, EncodeDeviceDetailResp> encodeDeviceCache = new HashMap<>();

            for (SyncCameraResp syncCameraResp : syncCameraResps) {
                DeviceDto deviceDto = deviceService.selectByUniqueId(syncCameraResp.getCameraIndexCode(), application.getTenantId());
                if (deviceDto == null) {
                    deviceDto = new DeviceDto();
                    deviceDto.setUniqueId(syncCameraResp.getCameraIndexCode());
                    deviceDto.setImei(syncCameraResp.getCameraIndexCode());
                    deviceDto.setOriginName(syncCameraResp.getCameraName());
                    deviceDto.setName(syncCameraResp.getCameraName());
                    deviceDto.setCreateTime(currentDate);

                    fill(deviceDto, application);


                    if (syncCameraResp.getEncodeDeviceDetailResp() != null) {
                        DeviceExtraAttrCls.AttrOfIntelligentMonitor attr = new DeviceExtraAttrCls.AttrOfIntelligentMonitor();
                        attr.setManagerIp(syncCameraResp.getEncodeDeviceDetailResp().getIp());
                        //从应用上查找账号和密码
                        ApplicationAccessConf.TemplateOfHikIscConf.NvrItem nvrItem = templateOfHikIscConf
                                .filterByHost(syncCameraResp.getEncodeDeviceDetailResp().getIp());
                        if (nvrItem != null) {
                            attr.setManagerUserName(nvrItem.getNvrUser());
                            attr.setManagerPassword(nvrItem.getNvrPwd());
                        }
                        deviceDto.setExtraAttr(JacksonUtils.toJsonString(attr));
                    }

                    deviceDtos.add(deviceDto);
                } else {

                    DeviceDto newlyDto = new DeviceDto();
                    newlyDto.setId(deviceDto.getId());
                    newlyDto.setOriginName(syncCameraResp.getCameraName());
                    newlyDto.setOnlineStatus((byte) ((syncCameraResp.getStatus() != null
                            && syncCameraResp.getStatus().equals(2)) ? 0 : 1));


                    if (syncCameraResp.getEncodeDeviceDetailResp() != null) {
                        DeviceExtraAttrCls.AttrOfIntelligentMonitor attr = DeviceExtraAttrCls.parseExtStr(DeviceExtraAttrCls.AttrOfIntelligentMonitor.class
                                , deviceDto.getExtraAttr());
                        if (attr == null) {
                            attr = new DeviceExtraAttrCls.AttrOfIntelligentMonitor();
                        }
                        attr.setManagerIp(syncCameraResp.getEncodeDeviceDetailResp().getIp());
                        //从应用上查找账号和密码
                        ApplicationAccessConf.TemplateOfHikIscConf.NvrItem nvrItem = templateOfHikIscConf.filterByHost(syncCameraResp.getEncodeDeviceDetailResp().getIp());
                        if (nvrItem != null) {
                            attr.setManagerUserName(nvrItem.getNvrUser());
                            attr.setManagerPassword(nvrItem.getNvrPwd());
                        }
                        newlyDto.setExtraAttr(JacksonUtils.toJsonString(attr));
                    }
                    deviceService.updateById(newlyDto);
                }
            }
            deviceService.saveBatch(deviceDtos);
            return true;
        } catch (Exception e) {
            log.error("海康 监控同步 syncOrRegisterDevices 异常", e);
        }
        return false;
    }

    @Override
    public boolean subscribeEvents(ApplicationDto application) {
        Map<String, List<Integer>> result = new HashMap<>();
        for (HikIscConstants.EventEnum eventEnum : EVENT_ENUMS) {
            List<Integer> list = result.get(eventEnum.getCallBackPath());
            if (CollectionUtils.isEmpty(list)) {
                list = new ArrayList<>();
                result.put(eventEnum.getCallBackPath(), list);
            }
            list.add(eventEnum.getEventCode());
        }

        ApplicationAccessConf.TemplateOfHikIscConf templateOfHikIscConf = ApplicationAccessConf
                .parseExtStr(ApplicationAccessConf.TemplateOfHikIscConf.class, application.getAccessConf());

        Preconditions.checkNotNull(templateOfHikIscConf);

        MonitorClient monitorInstance = HikClientBuilder.builder()
                .ak(templateOfHikIscConf.getAk())
                .sk(templateOfHikIscConf.getSk())
                .host(templateOfHikIscConf.getHost())
                .build(MonitorClient.class);

        String eventSubUrl = sysConfigService.getConfigValueByKey("GatewayInnerBaseUrl") + "/dmsapi/hikIscCollect/eventRcv/";
        result.keySet().forEach(o -> monitorInstance.eventSub(result.get(o).toArray(new Integer[0]), eventSubUrl + o));
        return true;
    }

    @Override
    public boolean sendCmd(DeviceDto deviceDto, DeviceCommandTemplateDto deviceCommandTemplateDto, Map<String, Object> params, Long cmdId) {
        return false;
    }


    @Override
    public List<StreamResp> getStreamUrls(List<DeviceDto> monitors) {
        Map<Long, MonitorClient> instanceMap = new HashMap<>();

        List<String> streams = new ArrayList<>();
        for (DeviceDto monitor : monitors) {
            Long applicationId = monitor.getApplicationId();
            String url = "";
            try {
                MonitorClient monitorInstance = instanceMap.computeIfAbsent(applicationId, aLong -> {
                    ApplicationDto applicationDto = applicationService.selectById(aLong);
                    ApplicationAccessConf.TemplateOfHikIscConf templateOfHikIscConf = ApplicationAccessConf
                            .parseExtStr(ApplicationAccessConf.TemplateOfHikIscConf.class, applicationDto.getAccessConf());

                    assert templateOfHikIscConf != null;
                    return HikClientBuilder.builder()
                            .ak(templateOfHikIscConf.getAk())
                            .sk(templateOfHikIscConf.getSk())
                            .host(templateOfHikIscConf.getHost())
                            .build(MonitorClient.class);
                });
                List<String> previewDefaultUrls = monitorInstance.previewDefaultUrl(Collections.singletonList(monitor.getUniqueId()));
                url = previewDefaultUrls.get(0);
            } catch (Exception e) {
                log.error("海康 监控对接 getStreamUrls 异常", e);
            }
            streams.add(url);
        }
        return streams.stream().map(v -> {
            if (v == null) {
                return null;
            }
            return new StreamResp(v, StreamResp.StreamType.HLS264);
        }).collect(Collectors.toList());
    }

    @Override
    public List<PlaybackPart> getPlaybackParts(DeviceDto monitor, Date startTime, Date endTime) {
        ApplicationDto applicationDto = applicationService.selectById(monitor.getApplicationId());
        ApplicationAccessConf.TemplateOfHikIscConf templateOfHikIscConf = ApplicationAccessConf
                .parseExtStr(ApplicationAccessConf.TemplateOfHikIscConf.class, applicationDto.getAccessConf());
        if (applicationDto == null) {
            return Lists.newArrayList();
        }

        MonitorClient monitorClient = HikClientBuilder.builder()
                .ak(templateOfHikIscConf.getAk())
                .sk(templateOfHikIscConf.getSk())
                .host(templateOfHikIscConf.getHost())
                .build(MonitorClient.class);


        List<PlaybackPart> list = new ArrayList<>();
        PlaybackPart playbackStreamUrl = new PlaybackPart();
        playbackStreamUrl.setStreamUrl(monitorClient.playbackUrls(monitor.getUniqueId(), "hls", 1, startTime, endTime));
//        playbackStreamUrl.setStreamUrl("https://dev-smartcity.quectel.com:10443/live/livestream.m3u8");
        playbackStreamUrl.setStartTime(startTime);
        playbackStreamUrl.setEndTime(endTime);
        list.add(playbackStreamUrl);
        return list;
    }
}
